package com.onpositive.collections;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;

import com.onpositive.notes.model.ITemplate;
import com.onpositive.notes.model.ITemplateModel;
import com.onpositive.notes.services.TemplateModelRegistry;

public class BasicCollection implements IObjectCollection {

	private static final long serialVersionUID = 4320530741197153000L;
	
	public BasicCollection() {
		super();
	}

	public BasicCollection(String name, IMemberValueCalculator calc) {
		super();
		this.name = name;
		this.calc = calc ;
	}

	private IMemberValueCalculator calc ;
	private String name ;
	private List<ICollectionDelta<?>> historyArray = new ArrayList<ICollectionDelta<?>>() ;
	private HashMap<Integer,ICollectionMember<?>> membersMap = new HashMap<Integer, ICollectionMember<?>>() ;
	private HashMap<Integer,ICollectionDelta<?>> deltaMap = new HashMap<Integer, ICollectionDelta<?>>() ;
	private HashSet<Integer> affectingTemplates = new HashSet<Integer>() ;
	private HashSet<String> affectingTemplateModels= new HashSet<String>() ;
	private HashMap<String, ArrayList<ICollectionMember<?>>> stringIndex = new HashMap<String, ArrayList<ICollectionMember<?>>>() ;
	private int id ;
	
	private int vacantDeltaId = 0 ;
	
	private int vacantMemberId = 0 ;
	
	@Override
	public String getName() {
		return name ;
	}

	@Override
	public List<ICollectionMember<?>> getMembersByFirstWord(String word) {
		return stringIndex.get(word);
	}

	@Override
	public List<ICollectionMember<?>> getAllMembers() {
		return new ArrayList<ICollectionMember<?>>( membersMap.values() );
	}

	@Override
	public List<ITemplateModel<?>> getAffectingTemplates() {
		
		ArrayList<ITemplateModel<?>> result = new ArrayList<ITemplateModel<?>>();
		
		for( String id : affectingTemplateModels ) {
			ITemplateModel<?> model = TemplateModelRegistry.getInstance().getModelById(id);
			result.add(model) ;
		}
		
		return result ;
	}

	@Override
	public List<ICollectionDelta<?>> getCompleteHistory() {
		return historyArray ;
	}

	@Override
	public List<ICollectionDelta<?>> getMemberHistory( ICollectionMember<?> member ) {
		
		int id = member.getId();
		ArrayList<ICollectionDelta<?>> result = new ArrayList<ICollectionDelta<?>>() ;
		for( ICollectionDelta<?> delta : historyArray ){			
			if( delta.getAffectedMembersIdList().contains( id ) )
				result.add(delta) ;
		}
		return result ;
	}

	@Override
	public ICollectionMember<?> getMemberById(int id) {
		return membersMap.get(id);
	}

	@Override
	public int registerDelta(ICollectionDelta<?> delta) {
		int deltaId = vacantDeltaId++ ; 
		delta.setId(deltaId) ;
		deltaMap.put( deltaId, delta ) ;
		historyArray.add( delta ) ;
		ITemplate template = delta.getTemplate();
		affectingTemplates.add( template.getId() ) ;
		affectingTemplateModels.add( template.getModel().getId() ) ;
		delta.setCollection(this) ;
		return deltaId ;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
		for( ICollectionDelta<?> delta : historyArray )
			delta.setCollection(this) ;
	}

	@Override
	public int addNewMember(ICollectionMember<?> member) {
		
		int memberId = vacantMemberId++ ;
		member.setId(memberId) ;
		member.setCollectionId( getId() ) ;
		
		membersMap.put( member.getId(), member ) ;
		
		String keyWord = constructKeyWord(member.getName());
		
		ArrayList<ICollectionMember<?>> lst = stringIndex.get(keyWord) ;
		if( lst == null ){
			lst = new ArrayList<ICollectionMember<?>>() ;
			stringIndex.put(keyWord, lst) ;
		}
		lst.add(member) ;
		
		return member.getId() ;
	}

	private String constructKeyWord( String memberName )
	{
		String str = memberName.trim().toLowerCase() ;
		int ind = str.indexOf(' ') ;
		if( ind < 0 )
			ind = str.length() ;
		
		String keyWord = str.substring(0, ind) ;
		return keyWord;
	}

	@Override
	public ICollectionMember<?> getMemberByName(String name) {
		
		String keyWord = constructKeyWord(name) ;
		ArrayList<ICollectionMember<?>> lst = stringIndex.get(keyWord) ;
		if( lst == null )
			return null ;
		
		String name_lc = name.toLowerCase();
		for( ICollectionMember<?> member : lst ){			
			if( member.getName().toLowerCase().equals(name_lc) )
				return member ;
		}
		
		return null;
	}

	@Override
	public void removeDelta(int deltaId) {
		ICollectionDelta<?> delta = deltaMap.get(deltaId) ;
		int ind = historyArray.indexOf(delta) ;
		historyArray.remove(ind) ;
		deltaMap.remove(deltaId) ;
	}
	
	@Override
	public String toString(){
		return "Collection "+getName() ;
	}

	@Override
	public Object getCurrentValue(ICollectionMember<?> member) {
		return calc.calculateValue(this, member);
	}

}
